package com.vic.Builder;

import com.vic.Utils.StringUtils;
import com.vic.bean.constant;
import com.vic.bean.fieldInfo;
import com.vic.bean.tableInfo;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;

/**
 * @Author: Vic Ly
 */
public class builderMapperXml {
    private static final Logger log = LoggerFactory.getLogger(builderMapperXml.class);
    // 通用列标记
    private static final String baseColumn = "base_column";
    // 基本查询条件
    private static final String baseQueryCondition = "base_condition";
    private static final String baseQueryExtendCondition = "base_condition_extend";
    private static final String QueryCondition = "query_condition";
    public static void execute(tableInfo tableInfo) {
        File folder = new File(constant.MAPPER_XML_PATH);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String xmlFileName = tableInfo.getBeanName() + constant.SUFFIX_MAPPER;
        File xmlFile = new File(folder,  xmlFileName+ ".xml");
        // 接下来对生成的文件写入内容
        OutputStream out = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        try {
            out = new FileOutputStream(xmlFile);
            osw = new OutputStreamWriter(out,"utf8");
            bw = new BufferedWriter(osw);

            bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
            bw.newLine();
            bw.write("<!DOCTYPE mapper");
            bw.newLine();
            bw.write("\t\tPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"");
            bw.newLine();
            bw.write("\t\t\"https://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
            bw.newLine();
            bw.write("<mapper namespace=\""+(constant.MAPPER_PACKAGE+"."+xmlFileName)+"\">");
            bw.newLine();
            bw.newLine();

            // resultMap
            bw.write("\t<!--基本实体映射-->");
            bw.newLine();
            String poClassName = constant.PACKAGE_PO +"."+ tableInfo.getBeanName();
            bw.write("\t<resultMap id=\"baseResultMap\" type=\""+poClassName+"\">");
            bw.newLine();
            fieldInfo idField = null;
            Map<String, List<fieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for(Map.Entry<String,List<fieldInfo>> entry : keyIndexMap.entrySet()){
                if("PRIMARY".equals(entry.getKey())){
                    List<fieldInfo> fieldInfoList = entry.getValue();
                    if(fieldInfoList.size() == 1){
                        idField = fieldInfoList.get(0);
                        break;
                    }
                }
            }
            for(fieldInfo fieldInfo:tableInfo.getFieldList()){
                bw.write("\t\t<!--"+fieldInfo.getComment() + "-->");
                bw.newLine();
                String key = "";
                if(idField != null && fieldInfo.getPropertyName().equals(idField.getPropertyName())){
                    key = "id";
                }else{
                    key = "result";
                }
                bw.write("\t\t<"+key+" column=\""+fieldInfo.getName()+"\" property=\""+fieldInfo.getPropertyName()+"\"/>");
                bw.newLine();
            }
            bw.write("\t</resultMap>");
            bw.newLine();
            bw.newLine();

            // 通用查询列
            bw.newLine();
            bw.write("\t<!--通用查询列-->");
            bw.newLine();
            bw.write("\t<sql id=\""+baseColumn+"\">");
            bw.newLine();
            StringBuilder column = new StringBuilder();
            for(fieldInfo fieldInfo:tableInfo.getFieldList()){
                column.append(fieldInfo.getName()).append(",");
            }
            String columnFinally = column.substring(0, column.lastIndexOf(","));
            bw.write("\t\t"+columnFinally);
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            // 基础查询条件
            bw.newLine();
            bw.write("\t<!--基础查询条件-->");
            bw.newLine();
            bw.write("\t<sql id=\""+baseQueryCondition+"\">");
            bw.newLine();
            for (fieldInfo fieldInfo:tableInfo.getFieldList()){
                String stringQuery = "";
                if(ArrayUtils.contains(constant.SQL_STRING,fieldInfo.getSqlType())){
                    stringQuery = " and query."+fieldInfo.getPropertyName() + " != ''";
                }
                bw.write("\t\t<if test=\"query."+fieldInfo.getPropertyName() + " != null"+stringQuery + "\">");
                bw.newLine();
                bw.write("\t\t\tand "+fieldInfo.getName()+" = #{query."+fieldInfo.getPropertyName() + "}");
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            // 扩展的查询条件
            bw.newLine();
            bw.write("\t<!--扩展的查询条件-->");
            bw.newLine();
            bw.write("\t<sql id=\""+baseQueryExtendCondition+"\">");
            bw.newLine();
            for (fieldInfo fieldInfo:tableInfo.getFieldExtendList()){
                String andWhere = "";
                if(ArrayUtils.contains(constant.SQL_STRING,fieldInfo.getSqlType())){
                    andWhere = "and "+fieldInfo.getName() + " like concat('%',#{query." +fieldInfo.getPropertyName()+"},'%')";
                } else if (ArrayUtils.contains(constant.SQL_DATE_TIME,fieldInfo.getSqlType())||ArrayUtils.contains(constant.SQL_DATE,fieldInfo.getSqlType())) {
                    if(fieldInfo.getPropertyName().endsWith(constant.SUFFIX_BEAN_QUERY_TIME_START)){
                        andWhere = "<![CDATA[ and "+fieldInfo.getName() + " >= str_to_date(#{query."+fieldInfo.getPropertyName()+"}, '%Y-%m-%d') ]]>";
                    } else if (fieldInfo.getPropertyName().endsWith(constant.SUFFIX_BEAN_QUERY_TIME_END)) {
                        andWhere = "<![CDATA[ and "+fieldInfo.getName() +" < date_sub(str_to_date(#{query."+fieldInfo.getPropertyName() + "},'%Y-%m-%d'),"+
                                "interval -1 day) ]]>";
                    }
                }
                bw.write("\t\t<if test=\"query."+fieldInfo.getPropertyName() + " != null and query."+fieldInfo.getPropertyName() + " != ''\">");
                bw.newLine();
                bw.write("\t\t\t"+andWhere);
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();


            // 通用查询条件
            bw.newLine();
            bw.write("\t<!--通用查询条件-->");
            bw.newLine();
            bw.write("\t<sql id=\""+QueryCondition+"\">");
            bw.newLine();
            bw.write("\t\t<where>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\""+baseQueryCondition+"\"/>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\""+baseQueryExtendCondition+"\"/>");
            bw.newLine();
            bw.write("\t\t</where>");
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            // 查询列表
            bw.newLine();
            bw.write("\t<!--查询列表-->");
            bw.newLine();
            bw.write("\t<select id=\"selectList\" resultMap=\"baseResultMap\">");
            bw.newLine();
            bw.write("\t\tSELECT <include refid=\""+baseColumn + "\"/> FROM "+tableInfo.getTableName() + " <include refid=\""+QueryCondition + "\"/>" );
            bw.newLine();
            bw.write("\t\t<if test=\"query.orderBy != null\"> order by ${query.orderBy} </if>");
            bw.newLine();
            bw.write("\t\t<if test=\"query.simplePage != null\"> limit #{query.simplePage.start},#{query.simplePage.end}</if>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();

            // 查询数量
            bw.newLine();
            bw.write("\t<!--查询数量-->");
            bw.newLine();
            bw.write("\t<select id=\"selectCount\" resultType=\"java.lang.Integer\">");
            bw.newLine();
            bw.write("\t\tSELECT count(1) FROM "+tableInfo.getTableName() + " <include refid=\""+QueryCondition + "\"/>" );
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();

            // 单条插入
            bw.newLine();
            bw.write("\t<!--插入(匹配有值的字段)-->");
            bw.newLine();
            bw.write("\t<insert id=\"insert\" parameterType=\""+constant.PACKAGE_PO+"."+tableInfo.getBeanName()+"\">");
            bw.newLine();

            fieldInfo autoIncrementField = null;
            for(fieldInfo fieldInfo : tableInfo.getFieldList()){
                if(null != fieldInfo.getAutoIncrement() && fieldInfo.getAutoIncrement()){
                    autoIncrementField = fieldInfo;
                    break;
                }
            }
            if(autoIncrementField != null){
                bw.write("\t\t<selectKey keyProperty=\"bean."+autoIncrementField.getName()+"\" resultType=\""+autoIncrementField.getJavaType()+"\" order=\"AFTER\">");
                bw.newLine();
                bw.write("\t\t\tSELECT LAST_INSERT_ID()");
                bw.newLine();
                bw.write("\t\t</selectKey>");
            }
            bw.newLine();
            bw.write("\t\tinsert into "+tableInfo.getTableName()+"");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (fieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+" != null \">");
                bw.newLine();
                bw.write("\t\t\t\t"+fieldInfo.getName()+",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (fieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+ "!=null\">");
                bw.newLine();
                bw.write("\t\t\t\t#{bean."+fieldInfo.getPropertyName()+"},");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();


            // 单条插入或更新
            bw.write("\t<!--插入或更新-->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdate\" parameterType=\""+constant.PACKAGE_PO+"."+tableInfo.getBeanName()+"\">");
            bw.newLine();
            bw.write("\t\tinsert into "+tableInfo.getTableName()+"");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (fieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+" != null \">");
                bw.newLine();
                bw.write("\t\t\t\t"+fieldInfo.getName()+",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for (fieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+ "!=null\">");
                bw.newLine();
                bw.write("\t\t\t\t#{bean."+fieldInfo.getPropertyName()+"},");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\ton DUPLICATE key update");
            bw.newLine();
            // Map<xx> 生成时去掉主键、唯一索引,这些列应该是不能改变的
            Map<String,String> keyTempMap = new HashMap();
            for(Map.Entry<String,List<fieldInfo>> entry: keyIndexMap.entrySet()){
                List<fieldInfo> fieldInfoList = entry.getValue();
                for(fieldInfo item:fieldInfoList){
                    keyTempMap.put(item.getName(), item.getName());
                }
            }
            bw.write("\t\t<trim prefix=\"\" suffix=\"\" suffixOverrides=\",\">");
            bw.newLine();
            for (fieldInfo fieldInfo : tableInfo.getFieldList()){
                if(keyTempMap.get(fieldInfo.getName())!= null){
                    continue;
                }
                bw.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+ "!=null\">");
                bw.newLine();
                bw.write("\t\t\t\t"+fieldInfo.getName()+" = VALUES("+fieldInfo.getName() + "),");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();

            // 批量插入
            bw.write("\t<!--批量插入-->");
            bw.newLine();
            bw.write("\t<insert id=\"insertBatch\" parameterType=\""+poClassName + "\">");
            bw.newLine();
            StringBuffer sb = new StringBuffer();
            StringBuffer sbParam = new StringBuffer();
            for(fieldInfo fieldInfo:tableInfo.getFieldList()){
                if(fieldInfo.getAutoIncrement()){
                    continue; // 去掉id(自增)
                }
                sb.append(fieldInfo.getName()).append(",");
                sbParam.append("#{item."+fieldInfo.getPropertyName()+"}").append(",");
            }
            String temp = sb.substring(0,sb.lastIndexOf(","));
            bw.write("\t\tinsert into "+tableInfo.getTableName() + "("+temp+")values");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\" >");
            bw.newLine();
            String tempParam = sbParam.substring(0,sbParam.lastIndexOf(","));
            bw.write("\t\t\t("+tempParam+")");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();


            // 批量插入或更新
            bw.write("\t<!--批量插入或更新-->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdateBatch\" parameterType=\""+poClassName + "\">");
            bw.newLine();
            temp = sb.substring(0,sb.lastIndexOf(","));
            bw.write("\t\tinsert into "+tableInfo.getTableName() + "("+temp+")values");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\" open=\"(\" close=\")\">");
            bw.newLine();
            tempParam = sbParam.substring(0,sbParam.lastIndexOf(","));
            bw.write("\t\t\t"+tempParam);
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();
            bw.write("\t\ton DUPLICATE key update ");
            StringBuffer sbBatchParam = new StringBuffer();
            for(fieldInfo fieldInfo:tableInfo.getFieldList()){
                sbBatchParam.append(fieldInfo.getName()+" = VALUES("+fieldInfo.getName()+"),");
            }
            String tempSbBatchParam = sbBatchParam.substring(0,sbBatchParam.lastIndexOf(","));
            bw.write(tempSbBatchParam);
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();

            //根据crud
            for(Map.Entry<String,List<fieldInfo>> entry:keyIndexMap.entrySet()){
                List<fieldInfo> keyFieldInfoList = entry.getValue();

                Integer index = 0;
                StringBuilder methodName = new StringBuilder();
                StringBuffer paramsName = new StringBuffer();
                for(fieldInfo fieldInfo:keyFieldInfoList){
                    index++;
                    methodName.append(StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()));
                    paramsName.append(fieldInfo.getName() + "=#{"+fieldInfo.getPropertyName()+"}");
                    if(index < keyFieldInfoList.size()){
                        methodName.append("And");
                        paramsName.append(" and ");
                    }
                }
                bw.write("\t<!--根据"+methodName+"查询-->");
                bw.newLine();
                bw.write("\t<select id=\"selectBy"+methodName+"\" resultMap=\"baseResultMap\">");
                bw.newLine();
                bw.write("\t\tselect <include refid=\""+baseColumn+"\"/> from "+tableInfo.getTableName()+" where "+paramsName);
                bw.newLine();
                bw.write("\t</select>");
                bw.newLine();
                bw.newLine();

                bw.write("\t<!--根据"+methodName+"更新-->");
                bw.newLine();
                bw.write("\t<update id=\"updateBy"+methodName+"\" parameterType=\""+poClassName+"\">");
                bw.newLine();
                bw.write("\t\tupdate "+tableInfo.getTableName());
                bw.newLine();
                bw.write("\t\t<set>");
                bw.newLine();
                for(fieldInfo fieldInfo:tableInfo.getFieldList()){
                    bw.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+"!= null\">");
                    bw.newLine();
                    bw.write("\t\t\t\t"+fieldInfo.getName() + " = #{bean."+fieldInfo.getPropertyName()+"},");
                    bw.newLine();
                    bw.write("\t\t\t</if>");
                    bw.newLine();
                }
                bw.write("\t\t</set>");
                bw.newLine();
                bw.write("\t\twhere "+paramsName);
                bw.newLine();
                bw.write("\t</update>");
                bw.newLine();
                bw.newLine();

                bw.write("\t<!--根据"+methodName+"删除-->");
                bw.newLine();
                bw.write("\t<delete id=\"deleteBy"+methodName+"\">");
                bw.newLine();
                bw.write("\t\tdelete from "+tableInfo.getTableName() + " where "+paramsName);
                bw.newLine();
                bw.write("\t</delete>");
                bw.newLine();
            }
            bw.write("</mapper>");
            bw.flush();

        }catch (Exception e){
            log.error("创建MapperXml文件失败",e);
        }finally {
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(osw != null){
                try {
                    osw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}























